eletrotupi / tcc/ frontend/app/triggers/[id].tsxfd21c7f08eddd7a1198b4c46080186820aa30a6c
6.2 KB | 240 lines Raw
1
import { useState, useEffect, use } from "react";
2
import {
3
  StyleSheet,
4
  Text,
5
  View,
6
  ScrollView,
7
  Pressable,
8
  ActivityIndicator,
9
} from "react-native";
10
import { useLocalSearchParams, router, Stack } from "expo-router";
11
import { format } from "date-fns";
12
import { ptBR } from "date-fns/locale";
13

14
import { Card, SubtleInfoCard } from "@/components/ui/Cards";
15
import { Badge } from "@/components/ui/Badge";
16
import { Button } from "@/components/ui/Button";
17
import { Col, Between, Row } from "@/components/ui/LayoutHelpers";
18
import { Section, SectionHeader } from "@/components/ui/Sections";
19
import { Theme, Typography, Colors, Spacing } from "@/constants/theme";
20
import { MaterialIcons } from "@expo/vector-icons";
21
import { getTriggerCategory } from "@/constants/trigger-categories";
22
import {
23
  useTrigger,
24
  useDeleteTrigger,
25
} from "@/hooks/useTrigger.queries";
26
import { formatMoment } from "@/lib/utils/time";
27

28
export default function TriggerDetailsScreen() {
29
  const { id } = useLocalSearchParams<{ id: string }>();
30
  const { data: trigger, isLoading, isError } = useTrigger(id);
31
  const deleteTrigger = useDeleteTrigger();
32
  const [minutesLeft, setMinutesLeft] = useState(0);
33
  const [canDelete, setCanDelete] = useState(false);
34

35
  useEffect(() => {
36
    const updateTimer = () => {
37
      const createdAt = new Date(trigger?.createdAt);
38
      if (!createdAt) return;
39

40
      const msSinceCreation = Date.now() - createdAt.getTime();
41
      const deletionWindowMs = 5 * 60 * 1000;
42

43
      const newCanDelete = msSinceCreation < deletionWindowMs;
44
      const newMinutesLeft = Math.max(
45
        0,
46
        Math.ceil((deletionWindowMs - msSinceCreation) / 60000),
47
      );
48

49
      setCanDelete(newCanDelete);
50
      setMinutesLeft(newMinutesLeft);
51
    };
52

53
    if (isLoading) return;
54

55
    updateTimer(); // Set initial values
56

57
    const interval = setInterval(updateTimer, 1000);
58

59
    return () => clearInterval(interval);
60
  }, [trigger, isLoading]);
61

62
  console.log("trigger", trigger)
63
  console.log("isLoading", isLoading)
64

65
  if (isLoading) {
66
    return (
67
      <View style={styles.centered}>
68
        <ActivityIndicator size="large" color={Colors.light.tint} />
69
      </View>
70
    );
71
  }
72

73
  if (isError || !trigger) {
74
    return (
75
      <View style={styles.centered}>
76
        <Text style={styles.errorText}>Registro não encontrado.</Text>
77
        <Pressable onPress={() => router.back()} style={styles.backButton}>
78
          <Text style={styles.backButtonText}>Voltar</Text>
79
        </Pressable>
80
      </View>
81
    );
82
  }
83

84
  const meta = getTriggerCategory(trigger.category);
85

86
  const handleDelete = async () => {
87
    await deleteTrigger.mutateAsync(String(trigger.id));
88

89
    router.back();
90
  };
91

92
  const deleteButtonMsg = () => {
93
    const msg = "Excluir Registro";
94
    const timeLeftStr = `(Disponível por ${minutesLeft < 1 ? "<1" : minutesLeft}:00)`;
95
    const suffix = canDelete ? timeLeftStr : "(Expirado)";
96

97
    return `${msg} ${suffix}`;
98
  };
99

100
  return (
101
    <>
102
      <Stack.Screen options={{ title: "Ver detalhes" }} />
103

104
      <ScrollView
105
        style={styles.container}
106
        contentContainerStyle={styles.content}
107
        showsVerticalScrollIndicator={false}
108
      >
109
        {/* Header card */}
110
        <Card style={styles.headerCard}>
111
          <Row style={{ alignItems: "center" }}>
112
            <View style={[styles.iconWrap, { backgroundColor: meta.iconBackground }]}>
113
              <MaterialIcons name={meta.icon} size={22} color={meta.color} />
114
            </View>
115

116
            <Col gap={2}>
117
              <Text style={styles.triggerLabel}>
118
                {meta.label}
119
              </Text>
120
              <Text style={styles.triggerMoment}>
121
                {formatMoment(new Date(trigger.moment))}
122
              </Text>
123
            </Col>
124
          </Row>
125
        </Card>
126

127
        {/* Annotation / notes */}
128
        {trigger.comment && (
129
          <Section>
130
            <SectionHeader title="Anotações" variant="subtle" />
131
            <Card style={{ padding: Spacing.cardGap }}>
132
              <Text style={styles.annotation}>
133
                "{trigger.comment?.trim()}"
134
              </Text>
135
            </Card>
136
          </Section>
137
        )}
138

139
        {/* Delete */}
140
        <View style={styles.section}>
141
          <Text style={styles.sectionLabel}>GESTÃO DO REGISTRO</Text>
142
          <Button
143
            variant="danger"
144
            isLoading={deleteTrigger.isPending}
145
            disabled={!canDelete || deleteTrigger.isPending}
146
            onPress={handleDelete}
147
            title={deleteButtonMsg()}
148
          />
149

150
          <SubtleInfoCard
151
            style={styles.deleteInfo}
152
            text={`
153
              A exclusão de registros é permitida apenas nos primeiros 5 minutos
154
              após o envio para garantir a integridade do histórico emocional.
155
              `}
156
          />
157
        </View>
158
      </ScrollView>
159
    </>
160
  );
161
}
162

163
const styles = StyleSheet.create({
164
  container: {
165
    flex: 1,
166
    backgroundColor: Theme.colors.background,
167
  },
168
  content: {
169
    padding: Spacing.containerPadding,
170
    gap: Spacing.sectionGap,
171
    paddingBottom: 48,
172
  },
173
  iconWrap: {
174
    width: 40,
175
    height: 40,
176
    borderRadius: 20,
177
    alignItems: 'center',
178
    justifyContent: 'center',
179
    marginTop: 1
180
  },
181
  headerCardContent: {
182
    flexDirection: "row",
183
    alignItems: "center",
184
    gap: 8,
185
  },
186
  triggerLabel: {
187
    ...Typography.headlineLg,
188
    color: Colors.light.text,
189
  },
190
  centered: {
191
    flex: 1,
192
    justifyContent: "center",
193
    alignItems: "center",
194
    gap: 12,
195
  },
196
  errorText: {
197
    fontSize: 15,
198
    color: Colors.light.textSecondary,
199
  },
200
  backButton: {
201
    paddingHorizontal: 20,
202
    paddingVertical: 10,
203
    backgroundColor: Theme.colors.tint,
204
    borderRadius: Theme.borderRadius.md,
205
  },
206
  backButtonText: {
207
    fontWeight: "700",
208
    color: Theme.colors.text,
209
  },
210

211
  // Header
212
  headerCard: {
213
    padding: 16,
214
  },
215
  triggerMoment: {
216
    fontSize: 13,
217
    color: Colors.light.textSecondary,
218
  },
219

220
  // Sections
221
  section: {
222
    gap: 8,
223
  },
224
  sectionLabel: {
225
    fontSize: 11,
226
    fontWeight: "600",
227
    letterSpacing: 0.8,
228
    color: Colors.light.textSecondary,
229
    textTransform: "uppercase",
230
  },
231

232
  // Annotation
233
  annotation: {
234
    fontSize: 14,
235
    lineHeight: 22,
236
    color: Colors.light.textSecondary,
237
    fontStyle: "italic",
238
    padding: 4,
239
  },
240
});